package com.dataart.training.crimequalification.matching;

import com.dataart.training.crimequalification.domain.CrimeDetails;
import com.dataart.training.crimequalification.domain.CrimeObject;
import com.dataart.training.crimequalification.domain.Guilt;
import com.dataart.training.crimequalification.domain.SubjectiveSide;
import com.dataart.training.crimequalification.entity.CrimeConsequenceEntity;
import com.dataart.training.crimequalification.entity.CrimeSubjectEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class CrimeDetailsMatchingServiceImpl implements CrimeDetailsMatchingService {

    //-----------------------------------------------------------------

    private static final Logger logger = LoggerFactory
            .getLogger(CrimeDetailsMatchingServiceImpl.class);

    //----------------------------------------------------------------------

    /**
     * @param crimeObjectOne
     * @param crimeObjectTwo
     * @return
     */
    @Override
    public MatchingResult matchCrimeObjects(CrimeObject crimeObjectOne, CrimeObject crimeObjectTwo) {

        MatchingResult result = new MatchingResult();
        result.setMatches(true);
        StringBuilder verboseBuilder = new StringBuilder();

        int pointsGained = 0;
        int totalPoints = 3;


        if (!crimeObjectOne.getCrimeObjectEntity().getCodeName().equals(
                crimeObjectTwo.getCrimeObjectEntity().getCodeName()
        )) {

            verboseBuilder.append("\nНеверно определен основной объект.");
            result.setMatches(false);

        } else {
            verboseBuilder.append("\nОсновной объект определен верно.");
            pointsGained++;
        }

        if (crimeObjectOne.isWithFacultativeObject() != crimeObjectTwo.isWithFacultativeObject()) {
            //verboseBuilder.append("\nНе совпадает наличие факультативного объекта.");
            result.setMatches(false);
        } else {
            //verboseBuilder.append("\nНаличие факультативного объекта совпадает.");
        }

        if (crimeObjectOne.isWithFacultativeObject() && crimeObjectTwo.isWithFacultativeObject()) {
            if (!crimeObjectOne.getFacultativeCrimeObjectEntity().getCodeName().equals(
                    crimeObjectTwo.getFacultativeCrimeObjectEntity().getCodeName()
            )) {
                verboseBuilder.append("\nФакультативный объект определен неверно.");
                result.setMatches(false);
            }
        } else {
            verboseBuilder.append("\nФакультативный объект определен верно.");
            pointsGained++;
        }

        if (crimeObjectOne.isWithSupplementaryObject() != crimeObjectTwo.isWithSupplementaryObject()) {
            // verboseBuilder.append("\nНе совпадает наличие дополнительного объекта.");
            result.setMatches(false);
        } else {
            // verboseBuilder.append("\nНаличие дополнительного объекта совпадает.");
        }

        if (crimeObjectOne.isWithSupplementaryObject() && crimeObjectTwo.isWithSupplementaryObject()) {
            if (!crimeObjectOne.getSupplementaryCrimeObjectEntity().getCodeName().equals(
                    crimeObjectTwo.getSupplementaryCrimeObjectEntity().getCodeName()
            )) {
                verboseBuilder.append("\nДополнительный объект определен неверно.");
                result.setMatches(false);

            } else {
                verboseBuilder.append("\nДополнительный объект определен верно.");
                pointsGained++;
            }
        }

        if (!crimeObjectOne.isWithSupplementaryObject() && !crimeObjectTwo.isWithSupplementaryObject()) {
            verboseBuilder.append("\nДополнительный объект определен верно.");
            pointsGained++;
        }

        if (result.isMatches()) {
            verboseBuilder.append("\nОбъект преступления определены верно.");
        }

        result.setVerboseResult(verboseBuilder.toString());
        result.setPointsGained(pointsGained);
        result.setTotalPoints(totalPoints);

        return result;

    }

    /**
     * @param crimeSubjectOne
     * @param crimeSubjectTwo
     * @return
     */
    @Override
    public MatchingResult matchCrimeSubjects(CrimeSubjectEntity crimeSubjectOne, CrimeSubjectEntity crimeSubjectTwo) {

        int pointsGained = 0;
        int totalPoints = 1;

        MatchingResult result = new MatchingResult();
        result.setMatches(true);
        StringBuilder verboseBuilder = new StringBuilder();

        if (!crimeSubjectOne.getCodeName().equals(
                crimeSubjectTwo.getCodeName()
        )) {
            verboseBuilder.append("\nСубъект преступления определен неверно.");
            result.setMatches(false);
        } else {
            verboseBuilder.append("\nСубъект преступления определен верно.");
            pointsGained++;
        }

        result.setVerboseResult(verboseBuilder.toString());
        result.setPointsGained(pointsGained);
        result.setTotalPoints(totalPoints);

        return result;

    }

    /**
     * @param crimeDetailsOne
     * @param crimeDetailsTwo
     * @return
     */
    @Override
    public MatchingResult matchWholeCrimeDetails(CrimeDetails crimeDetailsOne, CrimeDetails crimeDetailsTwo) {

        MatchingResult objectMatchResult = matchCrimeObjects(crimeDetailsOne.getCrimeObject(),
                crimeDetailsTwo.getCrimeObject());
        MatchingResult subjectMatchResult = matchCrimeSubjects(crimeDetailsOne.getCrimeSubject(),
                crimeDetailsTwo.getCrimeSubject());
        MatchingResult subjSideMatchingResult = matchSubjectiveSides(crimeDetailsOne.getSubjectiveSide(),
                crimeDetailsTwo.getSubjectiveSide());
        MatchingResult consMatchingResult = matchConsequences(crimeDetailsOne.getCrimeConsequence(),
                crimeDetailsTwo.getCrimeConsequence());

        MatchingResult result = new MatchingResult();

        result.setMatches(subjectMatchResult.isMatches() && objectMatchResult.isMatches()
                && subjSideMatchingResult.isMatches() && consMatchingResult.isMatches());

        result.setVerboseResult(new StringBuilder().
                append(objectMatchResult.getVerboseResult()).
                append(subjectMatchResult.getVerboseResult()).
                append(subjSideMatchingResult.getVerboseResult()).
                append(consMatchingResult.getVerboseResult()).
                toString());

        int pointsGained = objectMatchResult.getPointsGained() + subjectMatchResult.getPointsGained()
                + subjSideMatchingResult.getPointsGained() + consMatchingResult.getPointsGained();

        int totalPoints = objectMatchResult.getTotalPoints() + subjectMatchResult.getTotalPoints()
                + subjSideMatchingResult.getTotalPoints() + consMatchingResult.getTotalPoints();

        result.setTotalPoints(totalPoints);
        result.setPointsGained(pointsGained);

        return result;

    }

    /**
     * @param subjSideOne
     * @param subjSideTwo
     * @return
     */
    @Override
    public MatchingResult matchSubjectiveSides(SubjectiveSide subjSideOne, SubjectiveSide subjSideTwo) {

        int pointsGained = 0;
        int totalPoints = 1;

        MatchingResult result = new MatchingResult();
        result.setMatches(true);
        StringBuilder verboseBuilder = new StringBuilder();

        Guilt guiltOne = subjSideOne.getGuilt();
        Guilt guiltTwo = subjSideTwo.getGuilt();

        if ((guiltTwo.isWithIntent() && !guiltOne.isWithIntent() ||
                (guiltTwo.isWithIndiscretion() && !guiltOne.isWithIndiscretion()))) {
            verboseBuilder.append("\nНеверно определен тип вины.");
            result.setMatches(false);
        } else {
            verboseBuilder.append("\nТип вины определен верно.");
            pointsGained++;
        }

        if (guiltOne.isWithIntent() && guiltTwo.isWithIntent()) {

            if (!guiltOne.getIntent().getCodeName().equals(guiltTwo.getIntent().getCodeName())) {
                verboseBuilder.append("\nВид умысла определен неверно.");
                result.setMatches(false);
            }
            verboseBuilder.append("\nВид умысла определен верно.");
            pointsGained++;
        }

        result.setVerboseResult(verboseBuilder.toString());
        result.setPointsGained(pointsGained);
        result.setTotalPoints(totalPoints);

        return result;

    }

    /**
     * @param consequenceOne
     * @param consequenceTwo
     * @return
     */
    @Override
    public MatchingResult matchConsequences(CrimeConsequenceEntity consequenceOne,
                                            CrimeConsequenceEntity consequenceTwo) {
        MatchingResult result = new MatchingResult();
        result.setMatches(true);

        int pointsGained = 0;
        int totalPoints = 1;

        StringBuilder verboseBuilder = new StringBuilder();

        if (!consequenceOne.getCodeName().equals(
                consequenceTwo.getCodeName()
        )) {
            verboseBuilder.append("\nПоследствие преступления определено неверно.");
            result.setMatches(false);
        } else {
            verboseBuilder.append("\nПоследствие преступления определено верно.");
            pointsGained++;
        }

        result.setVerboseResult(verboseBuilder.toString());
        result.setPointsGained(pointsGained);
        result.setTotalPoints(totalPoints);


        return result;
    }
}
